package View;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionListener;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.DefaultTableModel;
import org.jfree.chart.*;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;


public class MainView extends JPanel{

	private GridBagConstraints gbcRegulafalsi = new GridBagConstraints();	
	private GridBagConstraints gbcNewton = new GridBagConstraints();	
	
	private JPanel regulafalsiPanel = new JPanel();
	private JPanel newtonPanel = new JPanel();	
	private JPanel chartPanelRegulaFalsi = new JPanel();
	private JPanel chartPanelNewtons = new JPanel();
	
	
	private JLabel lblRX0 = new JLabel("x0");
	private JLabel lblRX1 = new JLabel("x1");
	private JLabel lblRIteration = new JLabel("Number of Iterations");
	private JLabel lblRFunction = new JLabel("Function");
	private JLabel lblRThreshold = new JLabel("Threshold");
	private JTextField txtRX0 = new JTextField(10);
	private JTextField txtRX1 = new JTextField(10);
	private JTextField txtRIteration = new JTextField(10);
	private JTextField txtRFunction = new JTextField(10);
	private JTextField txtRThreshold = new JTextField(10);
	private JButton btnComputeRegulaFalsi = new JButton("Compute Regula Falsi");
	private JButton btnSimulateRegulaFalsi = new JButton("Compute & Simulate Regula Falsi");
	private DefaultTableModel modelRegulaFalsi;
	private JTable tableRegulaFalsi = new JTable(modelRegulaFalsi); 
	private JScrollPane scrollRegulaFalsi = new JScrollPane(tableRegulaFalsi);
	
	
	private JLabel lblNX = new JLabel("x");
	private JTextField txtNX = new JTextField(10);
	private JLabel lblNIteration = new JLabel("Number of Iterations");
	private JLabel lblNFunction = new JLabel("Function");
	private JLabel lblNThreshold = new JLabel("Threshold");
	private JTextField txtNIteration = new JTextField(10);
	private JTextField txtNFunction = new JTextField(10);
	private JTextField txtNThreshold = new JTextField(10);
	private JButton btnComputeNewtons = new JButton("Compute Newtons");
	private JButton btnSimulateNewtons = new JButton("Compute & Simulate Newtons");
	private DefaultTableModel modelNewton;
	private JTable tableNewton = new JTable(modelNewton); 
	private JScrollPane scrollNewton = new JScrollPane(tableNewton);
	
	private ArrayList<Double> trueRegulaXList;
	private ArrayList<Double> trueRegulaYList;
	private ArrayList<Double> trueNewtonsXList;
	private ArrayList<Double> trueNewtonsYList;
	
	private XYSeries regulaFalsiSeries = new XYSeries("Approximated Value");
	private XYSeriesCollection regulaFalsiDataSet = new XYSeriesCollection();
	private XYSeries trueRegulaFalsiSeries = new XYSeries("True Value");
	private XYSeries newtonsSeries = new XYSeries("Approximated Value");
	private XYSeries trueNewtonsSeries = new XYSeries("True Value");
	private XYSeriesCollection newtonsDataSet = new XYSeriesCollection();
	
	public MainView() {
		setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
		regulafalsiPanel.setLayout(new GridBagLayout());
		newtonPanel.setLayout(new GridBagLayout());
		
		trueRegulaXList = new ArrayList<Double>();
		trueRegulaYList = new ArrayList<Double>();
		trueNewtonsXList = new ArrayList<Double>();
		trueNewtonsYList = new ArrayList<Double>();
		
		gbcRegulafalsi.gridx = 0;
		gbcRegulafalsi.gridy = 0;
		regulafalsiPanel.add(lblRX0, gbcRegulafalsi);
		gbcRegulafalsi.gridx = 1;
		gbcRegulafalsi.gridy = 0;
		regulafalsiPanel.add(txtRX0, gbcRegulafalsi);
		
		gbcRegulafalsi.gridx = 0;
		gbcRegulafalsi.gridy = 1;
		regulafalsiPanel.add(lblRX1, gbcRegulafalsi);
		gbcRegulafalsi.gridx = 1;
		gbcRegulafalsi.gridy = 1;
		regulafalsiPanel.add(txtRX1, gbcRegulafalsi);
		
		gbcRegulafalsi.gridx = 0;
		gbcRegulafalsi.gridy = 2;
		regulafalsiPanel.add(lblRIteration, gbcRegulafalsi);
		gbcRegulafalsi.gridx = 1;
		gbcRegulafalsi.gridy = 2;
		regulafalsiPanel.add(txtRIteration, gbcRegulafalsi);
		
		gbcRegulafalsi.gridx = 0;
		gbcRegulafalsi.gridy = 3;
		regulafalsiPanel.add(lblRFunction, gbcRegulafalsi);
		gbcRegulafalsi.gridx = 1;
		gbcRegulafalsi.gridy = 3;
		regulafalsiPanel.add(txtRFunction, gbcRegulafalsi);
		
		gbcRegulafalsi.gridx = 0;
		gbcRegulafalsi.gridy = 4;
		regulafalsiPanel.add(lblRThreshold, gbcRegulafalsi);
		gbcRegulafalsi.gridx = 1;
		gbcRegulafalsi.gridy = 4;
		regulafalsiPanel.add(txtRThreshold, gbcRegulafalsi);
		
		gbcRegulafalsi.gridx = 0;
		gbcRegulafalsi.gridy = 5;
		regulafalsiPanel.add(btnComputeRegulaFalsi, gbcRegulafalsi);
		
		gbcRegulafalsi.gridx = 1;
		gbcRegulafalsi.gridy = 5;
		regulafalsiPanel.add(btnSimulateRegulaFalsi, gbcRegulafalsi);
		
		gbcRegulafalsi.gridwidth = 2;
		gbcRegulafalsi.gridx = 0;
		gbcRegulafalsi.gridy = 6;
		modelRegulaFalsi = new DefaultTableModel(
				new Object[][] {
						{null, null, null, null, null, null, null},
					},
					new String[] {
						"x0", "x1", "x2", "y0", "y1", "y2", "Threshold"
					}
			);
		scrollRegulaFalsi.setPreferredSize(new Dimension(453,200));
		regulafalsiPanel.add(scrollRegulaFalsi, gbcRegulafalsi);
		
		chartPanelRegulaFalsi = new ChartPanel(createChart("Graph for Regula Falsi", regulaFalsiDataSet));
		chartPanelRegulaFalsi.setPreferredSize(new Dimension(800,310));
		gbcRegulafalsi.gridheight = 6;
		gbcRegulafalsi.gridwidth = 2;
		gbcRegulafalsi.gridx = 3;
		gbcRegulafalsi.gridy = 1;
		regulafalsiPanel.add(chartPanelRegulaFalsi, gbcRegulafalsi);
		
		
		gbcNewton.gridx = 0;
		gbcNewton.gridy = 0;
		newtonPanel.add(lblNX, gbcNewton);
		gbcNewton.gridx = 1;
		gbcNewton.gridy = 0;
		newtonPanel.add(txtNX, gbcNewton);
		
		gbcNewton.gridx = 0;
		gbcNewton.gridy = 1;
		newtonPanel.add(lblNIteration, gbcNewton);
		gbcNewton.gridx = 1;
		gbcNewton.gridy = 1;
		newtonPanel.add(txtNIteration, gbcNewton);
		
		gbcNewton.gridx = 0;
		gbcNewton.gridy = 2;
		newtonPanel.add(lblNFunction, gbcNewton);
		gbcNewton.gridx = 1;
		gbcNewton.gridy = 2;
		newtonPanel.add(txtNFunction, gbcNewton);
		
		gbcNewton.gridx = 0;
		gbcNewton.gridy = 3;
		newtonPanel.add(lblNThreshold, gbcNewton);
		gbcNewton.gridx = 1;
		gbcNewton.gridy = 3;
		newtonPanel.add(txtNThreshold, gbcNewton);
		
		gbcNewton.gridx = 0;
		gbcNewton.gridy = 4;
		newtonPanel.add(btnComputeNewtons, gbcNewton);
		
		gbcNewton.gridx = 1;
		gbcNewton.gridy = 4;
		newtonPanel.add(btnSimulateNewtons, gbcNewton);
		
		gbcNewton.gridwidth = 2;
		gbcNewton.gridx = 0;
		gbcNewton.gridy = 5;
		modelNewton = new DefaultTableModel(
				new Object[][] {
						{null, null, null, null},
					},
					new String[] {
						"x0", "f(x)", "f'(x)", "Threshold"
					}
			);
		scrollNewton.setPreferredSize(new Dimension(453,200));
		newtonPanel.add(scrollNewton, gbcNewton);
		
		chartPanelNewtons = new ChartPanel(createChart("Graph for Newtons", newtonsDataSet));
		chartPanelNewtons.setPreferredSize(new Dimension(800,280));
		gbcNewton.gridheight = 5;
		gbcNewton.gridwidth = 2;
		gbcNewton.gridx = 3;
		gbcNewton.gridy = 1;
		newtonPanel.add(chartPanelNewtons, gbcNewton);
		
		


		scrollRegulaFalsi.setViewportView(tableRegulaFalsi);
		tableRegulaFalsi.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		TableColumnAdjuster adjuster = new TableColumnAdjuster(tableRegulaFalsi);
		adjuster.setDynamicAdjustment(true);
		adjuster.adjustColumns();
		tableRegulaFalsi.setModel(modelRegulaFalsi);
		
		scrollNewton.setViewportView(tableNewton);
		tableNewton.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		adjuster = new TableColumnAdjuster(tableNewton);
		adjuster.setDynamicAdjustment(true);
		adjuster.adjustColumns();
		tableNewton.setModel(modelNewton);
		
		add(regulafalsiPanel);
		add(newtonPanel);
		regulafalsiPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), "Regula Falsi")); 
		newtonPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), "Newton's")); 

	}

	public Double getX0() {
		return Double.parseDouble(txtRX0.getText())+0.0;
	}

	public Double getX1() {
		return Double.parseDouble(txtRX1.getText())+0.0;
	}

	public int getRIteration() {
		return Integer.parseInt(txtRIteration.getText());
	}

	public String getRFunction() {
		return txtRFunction.getText();
	}

	public double getRThreshold() {
		return Double.parseDouble(txtRThreshold.getText())+0.0;
	}

	public Double getNX() {
		return Double.parseDouble(txtNX.getText())+0.0;
	}

	public int getNIteration() {
		return Integer.parseInt(txtNIteration.getText());
	}

	public String getNFunction() {
		return txtNFunction.getText();
	}

	public double getNThreshold() {
		return Double.parseDouble(txtNThreshold.getText())+0.0;
	}
	
	public void setSimulateRegulaFalsiListener(ActionListener action) {
		btnSimulateRegulaFalsi.addActionListener(action);
	}
	
	public void setSimulateNewtonsListener(ActionListener action) {
		btnSimulateNewtons.addActionListener(action);
	}
	
	public void setRegulaFalsiListener(ActionListener action) {
		btnComputeRegulaFalsi.addActionListener(action);
	}
	
	public void setNewtonsListener(ActionListener action) {
		btnComputeNewtons.addActionListener(action);
	}
	
	public JFreeChart createChart(String title, XYSeriesCollection dataset) {
        JFreeChart lineChart = ChartFactory.createXYLineChart(title,"X","Y",dataset,PlotOrientation.VERTICAL, true, true, false);
        lineChart.setBackgroundPaint(new Color(0, 0, 0, 0));
        
        XYPlot plot = lineChart.getXYPlot();
        plot.setBackgroundPaint(Color.CYAN);
        plot.setDomainGridlinePaint(Color.black);
        plot.setRangeGridlinePaint(Color.black);
        
        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        renderer.setSeriesLinesVisible(1, true);
        renderer.setSeriesShapesVisible(1, false);
        plot.setRenderer(renderer);

        NumberAxis range = (NumberAxis) plot.getRangeAxis();
        range.setRange(0.0, 10.0);
        range.setAutoRange(true);
        
        return lineChart;
    }

	public void addNewtonsRow(Double x, Double y, Double prime, Double threshold) {
		modelNewton.addRow(new Object[]{x, y, prime, threshold});
	}
	
	public void addRegulaFalsiRow(Double x0, Double x1,
			Double x2, Double y0, Double y1, Double y2, Double threshold) {
		modelRegulaFalsi.addRow(new Object[]{x0, x1, x2, y0, y1, y2, threshold});
	}
	
	public void addRegulaFalsiList(Double trueX, Double trueY) {
		trueRegulaXList.add(trueX);
		trueRegulaYList.add(trueY);
	}
	
	public void addNewtonsList(Double trueX, Double trueY) {
		trueNewtonsXList.add(trueX);
		trueNewtonsYList.add(trueY);
	}

	public void setModelNewton(ArrayList<Double> xList,
			ArrayList<Double> yList, ArrayList<Double> yPrimeList, 
			ArrayList<Double> thresholdList, ArrayList<Double> trueXList, ArrayList<Double> trueYList) {
		for(int i = 0; i < xList.size(); i++)
			modelNewton.addRow(new Object[]{xList.get(i), yList.get(i), yPrimeList.get(i), thresholdList.get(i)});
		for(int i = 0; i < trueXList.size(); i++){
			trueNewtonsXList.add(trueXList.get(i));
			trueNewtonsYList.add(trueYList.get(i));
		}
	}

	public void setModelRegulaFalsi(ArrayList<Double> x0List,
			ArrayList<Double> x1List, ArrayList<Double> x2List,
			ArrayList<Double> y0List, ArrayList<Double> y1List,
			ArrayList<Double> y2List, ArrayList<Double> xList,
			ArrayList<Double> yList, ArrayList<Double> thresholdList) {
		for(int i = 0; i < x0List.size(); i++)
			modelRegulaFalsi.addRow(new Object[]{x0List.get(i), x1List.get(i), x2List.get(i)
					, y0List.get(i), y1List.get(i), y2List.get(i), thresholdList.get(i)});
		for(int i = 0; i < xList.size(); i++){
			trueRegulaXList.add(xList.get(i));
			trueRegulaYList.add(yList.get(i));
		}
	}

	public void updateNewtonsChart() {
		newtonPanel.revalidate();
		newtonsSeries.clear();
		newtonsDataSet.removeAllSeries();

		for(int i = 0; i < modelNewton.getRowCount(); i++)
			newtonsSeries.add(Double.parseDouble(modelNewton.getValueAt(i, 0).toString()), Double.parseDouble(modelNewton.getValueAt(i, 1).toString()));
		for(int i = 0; i < trueNewtonsXList.size(); i++)
			trueNewtonsSeries.add(trueNewtonsXList.get(i), trueNewtonsYList.get(i));
		
		newtonsDataSet.addSeries(newtonsSeries);
		newtonsDataSet.addSeries(trueNewtonsSeries);
		
		chartPanelNewtons = new ChartPanel(createChart("Graph for Newtons", newtonsDataSet));
		chartPanelNewtons.setPreferredSize(new Dimension(800,280));
		gbcNewton.gridheight = 5;
		gbcNewton.gridwidth = 2;
		gbcNewton.gridx = 3;
		gbcNewton.gridy = 1;
		newtonPanel.add(chartPanelNewtons, gbcNewton);
	}
	
	public void updateRegulaFalsiChart(){
		regulafalsiPanel.revalidate();
		regulaFalsiSeries.clear();
		regulaFalsiDataSet.removeAllSeries();
		
		for(int i = 0; i < modelRegulaFalsi.getRowCount(); i++){
			regulaFalsiSeries.add(Double.parseDouble(modelRegulaFalsi.getValueAt(i, 0).toString()), Double.parseDouble(modelRegulaFalsi.getValueAt(i, 3).toString()));	
			regulaFalsiSeries.add(Double.parseDouble(modelRegulaFalsi.getValueAt(i, 1).toString()), Double.parseDouble(modelRegulaFalsi.getValueAt(i, 4).toString()));	
		}
		for(int i = 0; i < trueRegulaXList.size(); i++)
			trueRegulaFalsiSeries.add(trueRegulaXList.get(i), trueRegulaYList.get(i));
		
		regulaFalsiDataSet.addSeries(regulaFalsiSeries);
		regulaFalsiDataSet.addSeries(trueRegulaFalsiSeries);
		
		chartPanelRegulaFalsi = new ChartPanel(createChart("Graph for Regula Falsi", regulaFalsiDataSet));
		chartPanelRegulaFalsi.setPreferredSize(new Dimension(800,310));
		gbcRegulafalsi.gridheight = 6;
		gbcRegulafalsi.gridwidth = 2;
		gbcRegulafalsi.gridx = 3;
		gbcRegulafalsi.gridy = 1;
		regulafalsiPanel.add(chartPanelRegulaFalsi, gbcRegulafalsi);
	}

	public void resetNewtons() {
		modelNewton.setRowCount(0);
		newtonsSeries.clear();
		trueNewtonsSeries.clear();
		trueNewtonsXList.clear();
		trueNewtonsYList.clear();
		newtonsDataSet.removeAllSeries();
	}
	
	public void resetRegulaFalsi() {
		modelRegulaFalsi.setRowCount(0);
		regulaFalsiSeries.clear();
		trueRegulaFalsiSeries.clear();
		trueRegulaXList.clear();
		trueRegulaYList.clear();
		regulaFalsiDataSet.removeAllSeries();
	}
	
	public void setComputeRegulaFalsiButtonEnabled(boolean bool){
		btnComputeRegulaFalsi.setEnabled(bool);
	}
	
	public void setComputeNewtonsButtonEnabled(boolean bool){
		btnComputeNewtons.setEnabled(bool);
	}

}
